//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __ELASTOS_HAT_H__
#define __ELASTOS_HAT_H__

#include <ddk/allocpage.h>

#define STACK_GROW_MAX_SIZE     64

EXTERN PageTabEntry *AllocPageTable();
EXTERN void FreePageTable(PageTabEntry *pPageTab);

class HAT
{
public:
    void Activate();

    bool_t LoadMap(
        uint_t vBase, uint_t vLimit, uint_t pBase,
        dword_t dwProtect, Boolean bIsFlushCache);

    void UnloadMap(uint_t vBase, uint_t vLimit);

    bool_t SetProtect(uint_t vBase, uint_t vLimit, dword_t dwProtect);

    void Dispose();

    HAT();
    inline void * operator new(size_t s);
    inline void operator delete(void *p);

    void SyncGlobalHAT();

private:
    PageDirEntry m_pageDir[c_uNumberOfPageDirEntries];

public:
    static inline HAT * GetCurrent();

    static void ActivateKHAT();

    static bool_t LoadKernelMap(
        uint_t vBase, uint_t vLimit, uint_t pBase, dword_t dwProtect);

    static void UnloadKernelMap(uint_t vBase, uint_t vLimit);

private:
    static HAT *s_pCurrent;
};

inline void * HAT::operator new(size_t s)
{
    return (HAT *)DzAllocKernelPages(2);
}

inline void HAT::operator delete(void *p)
{
    assert(HAT::GetCurrent() != (HAT *)p);
    DzFreeKernelPages(p, 2);
}

inline void HAT::Activate()
{
    if (this == GetCurrent()) return;

    s_pCurrent = this;

    FlushCache();
    SetPageDirAddress(PHYSADDR(this));
    FlushAllTlbs();
}

inline HAT * HAT::GetCurrent()
{
    return s_pCurrent;
}

#endif // __ELASTOS_HAT_H__
